package com.tx.studentManager.dao.base;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;


import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import com.tx.studentManager.model.BaseModel;
import com.tx.studentManager.utils.ReflectionUtils;

/**
 * 封装Hibernate原生API的DAO泛型基类.
 * 
 * 可在Service层直接使用,也可以扩展泛型DAO子类使用.
 * 参考Spring3.1后取消了HibernateTemplate,直接使用Hibernate原生API.
 * 
 * @param <T>
 *            DAO操作的对象类型
 * @param <PK>
 *            主键类型
 * 
 * @author 此生唯晴
 */

public abstract class BaseDao<T extends BaseModel, PK extends Serializable> {

	protected Logger logger = Logger.getLogger(getClass());

	@Autowired
	protected SessionFactory sessionFactory;

	/**
	 * 获取entity类型
	 * 
	 * @return
	 */
	public Class<T> getEntityClass() {
		return ReflectionUtils.getSuperClassGenricType(getClass());
	}

	/**
	 * 用于Dao层子类使用的构造函数. 通过子类的泛型定义取得对象类型Class. <br/>
	 * 
	 * eg. public class UserDao extends SimpleHibernateDao<User, Long>
	 */
	public BaseDao() {

	}

	/**
	 * 用于省略Dao层, 在Service层直接使用通用SimpleHibernateDao的构造函数. 在构造函数中定义对象类型Class.<br/>
	 * 
	 */
	public BaseDao(final SessionFactory sessionFactory,
			final Class<T> entityClass) {
		this.sessionFactory = sessionFactory;

	}

	/**
	 * 取得sessionFactory.
	 */
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	/**
	 * 采用@Autowired按类型注入SessionFactory,当有多个SesionFactory的时候Override本函数.
	 */
	@Autowired
	public void setSessionFactory(final SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	/**
	 * 取得当前Session.
	 */
	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	public Session openSession(){
		return sessionFactory.openSession();
	}
	public void closeSession(Session session){
		if (session!=null) {
			session.close();
		}
	}
	/**
	 * 保存对象
	 * 
	 * @param entity
	 * @return 成功返回保存对象，失败返回null
	 */
	public T save(final T entity) {
		Assert.notNull(entity, "操作对象entity不能为空");
		try {
			getSession().save(entity);
		} catch (HibernateException e) {
			e.printStackTrace();
			logger.debug("save entity:"
					+ JSONObject.fromObject(entity).toString() + " failure");
			return null;
		}
		logger.debug("save entity: " + JSONObject.fromObject(entity).toString()
				+ " success");
		return entity;
	}

	/**
	 * 保存新增或修改的对象.
	 */
	public T saveOrUpdate(T entity) {
		Assert.notNull(entity, "操作对象entity不能为空");
		try {
			getSession().saveOrUpdate(entity);
		} catch (HibernateException e) {
			// e.printStackTrace();
			logger.debug("save or update entity:"
					+ JSONObject.fromObject(entity).toString() + " failure");
			return null;
		}
		logger.debug("save or update entity: "
				+ JSONObject.fromObject(entity).toString() + " success");
		return entity;
	}

	/**
	 * 删除对象.
	 * 
	 * @param entity
	 *            对象必须是session中的对象或含id属性的transient对象.
	 */
	public boolean delete(final T entity) {
		Assert.notNull(entity, "entity should not be null!");
		try {
			getSession().delete(entity);
		} catch (Exception e) {
			return false;
			// e.printStackTrace();
		}
		return true;
	}

	/**
	 * 按id删除对象.
	 */
	public boolean delete(final PK id) {
		Assert.notNull(id, "id should not be null!");
		T obj = get(id);
		if (obj != null) {
			delete(obj);
		} else {
			return false;
		}
		return true;
	}

	public boolean update(T entity) {
		Assert.notNull(entity, "entity should not be null !");
		try {
			getSession().update(entity);
		} catch (HibernateException e) {
			// e.printStackTrace();
			logger.debug("update " + getEntityClass().getSimpleName() + "["
					+ JSONObject.fromObject(entity)
					+ "] failure,maybe the entity not exist");
			return false;
		}
		logger.debug("update entity: " + getEntityClass().getSimpleName() + "["
				+JSONObject.fromObject(entity)+ "] success");
		return true;
	}

	/**
	 * 按Criteria查询对象列表.
	 * 
	 * @param criterions
	 *            数量可变的Criterion.
	 */
	@SuppressWarnings("unchecked")
	protected List<T> find(final Criterion... criterions) {
		return createCriteria(criterions).list();
	}

	/**
	 * 按id获取对象.
	 */
	@SuppressWarnings("unchecked")
	public T get(final PK id) {
		Assert.notNull(id, "id should not be null!");
		return (T) getSession().get(getEntityClass(), id);
	}

	@SuppressWarnings("unchecked")
	public T load(final PK id) {
		Assert.notNull(id, "id should not be null!");
		Object obj = getSession().load(getEntityClass(), id);
		if (obj != null) {
			logger.debug("load by id:" + id);
			return (T) obj;
		} else {
			return null;
		}
	}

	/**
	 * 获取全部对象.
	 */
	public List<T> getAll() {
		return find();
	}

	/**
	 * 获取全部对象,支持排序.
	 * 
	 * @param orderBy
	 *            排序属性名称
	 * @param isAsc
	 *            排序方向是否升序.
	 */
	@SuppressWarnings("unchecked")
	public List<T> getAll(String orderBy, boolean isAsc) {
		Criteria c = createCriteria();
		if (isAsc) {
			c.addOrder(Order.asc(orderBy));
		} else {
			c.addOrder(Order.desc(orderBy));
		}
		return c.list();
	}

	/**
	 * 按属性查找对象列表,匹配方式为相等.
	 */
	public List<T> findBy(final String propertyName, final Object value) {
		Assert.hasText(propertyName, "propertyName should not be null!");
		Criterion criterion = Restrictions.eq(propertyName, value);
		return find(criterion);
	}

	/**
	 * 按属性查找唯一对象,匹配方式为相等.
	 */
	@SuppressWarnings("unchecked")
	public T findUniqueBy(final String propertyName, final Object value) {
		Assert.hasText(propertyName, "propertyName should not be null!");
		Criterion criterion = Restrictions.eq(propertyName, value);
		return (T) createCriteria(criterion).uniqueResult();
	}

	/**
	 * 按id列表获取对象.
	 */
	public List<T> findByIds(List<PK> ids) {
		if (null == ids || ids.isEmpty()) {
			return null;
		}
		return find(Restrictions.in(getIdName(), ids));
	}

	/**
	 * 按id列表获取对象.
	 * 
	 * @param ids
	 *            数组形式
	 */
	public List<T> findByIds(PK[] ids) {
		if (null == ids || 0 == ids.length) {
			return null;
		}
		List<PK> list = new ArrayList<PK>();
		for (PK id : ids) {
			list.add(id);
		}
		return findByIds(list);
	}

	/**
	 * 按HQL查询对象列表.
	 * 
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 */
	@SuppressWarnings("unchecked")
	public List<T> findWithHQL(final String hql, final Object... values) {
		return createQuery(hql, values).list();
	}

	/**
	 * 按HQL查询对象列表,获取前topCount条数据
	 * 
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 */
	@SuppressWarnings("unchecked")
	public List<T> findTop(final String hql, int topCount,
			final Object... values) {
		Assert.hasText(hql, "queryString should not be null!");
		Query query = getSession().createQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		query.setMaxResults(topCount);
		return query.list();
	}

	/**
	 * 按HQL查询对象列表.
	 * 
	 * @param values
	 *            命名参数,按名称绑定.
	 */
	@SuppressWarnings("unchecked")
	public List<T> findWithHQL(final String hql,
			final Map<String, Object> values) {
		return createQuery(hql, values).list();
	}

	@SuppressWarnings("unchecked")
	public List<T> namedFind(String queryName, Object... params) {
		return getNamedQuery(queryName, params).list();
	}

	@SuppressWarnings("unchecked")
	public List<T> namedFind(String queryName, Map<String, Object> values) {
		return getNamedQuery(queryName, values).list();
	}

	/**
	 * 按HQL查询唯一对象.
	 * 
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 */
	@SuppressWarnings("unchecked")
	public T findUnique(final String hql, final Object... values) {
		List<T> list = (List<T>) createQuery(hql, values).list();
		return list != null && list.size() > 0 ? list.get(0) : null;// .uniqueResult();
	}

	/**
	 * 按HQL查询唯一对象.
	 * 
	 * @param values
	 *            命名参数,按名称绑定.
	 */
	@SuppressWarnings("unchecked")
	public T findUnique(final String hql, final Map<String, Object> values) {
		return (T) createQuery(hql, values).uniqueResult();
	}

	@SuppressWarnings("unchecked")
	public T namedFindUnique(String queryName, Object... params) {
		return (T) getNamedQuery(queryName, params).uniqueResult();
	}

	@SuppressWarnings("unchecked")
	public T namedFindUnique(String queryName, Map<String, Object> values) {
		return (T) getNamedQuery(queryName, values).uniqueResult();
	}

	/**
	 * 按SQL查询唯一对象.
	 * 
	 * @author zhirong
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 */
	@SuppressWarnings("unchecked")
	public T findUniqueSQL(final String sql, final Object... values) {
		return (T) createSQLQuery(sql, values).uniqueResult();
	}

	/**
	 * 按SQL查询数据库.
	 * 
	 * @author 此生唯晴
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 */
	@SuppressWarnings("unchecked")
	public List<T> findWithSql(final String sql, final Object... values) {
		return (List<T>) createSQLQuery(sql, values)
				.addEntity(getEntityClass()).list();
	}

	/**
	 * 按SQL查询数据库.
	 * 
	 * @author 此生唯晴
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 */
	@SuppressWarnings("unchecked")
	public List<T> findWithSql(final String sql,
			final Map<String, Object> values) {
		return (List<T>) createSQLQuery(sql, values)
				.addEntity(getEntityClass()).list();
	}

	/**
	 * 按SQL查询唯一对象.
	 * 
	 * @author zhirong
	 * @param values
	 *            命名参数,按名称绑定.
	 */
	@SuppressWarnings("unchecked")
	public T findUniqueSQL(final String sql, final Map<String, Object> values) {
		return (T) createSQLQuery(sql, values).uniqueResult();
	}

	/**
	 * 执行HQL进行批量修改/删除操作.
	 */
	public int batchExecuteWithHql(final String hql, final Object... values) {
		return createQuery(hql, values).executeUpdate();
	}

	/**
	 * 执行HQL进行批量修改/删除操作.
	 * 
	 * @return 更新记录数.
	 */
	public int batchExecuteWithHql(final String hql,
			final Map<String, Object> values) {
		return createQuery(hql, values).executeUpdate();
	}

	/**
	 * 
	 * 根据sql执行删除更新操作
	 * 
	 * @param sql
	 * @param values
	 * @return
	 */
	public int batchExecuteWithSql(String sql, Map<String, Object> values) {
		return createSQLQuery(sql, values).executeUpdate();
	}

	/**
	 * 
	 * 根据sql执行删除更新操作
	 * 
	 * @param sql
	 * @param values
	 * @return
	 */
	public int batchExecuteWithSql(String sql, Object... values) {
		return createSQLQuery(sql, values).executeUpdate();
	}

	/**
	 * 根据查询HQL与参数列表创建Query对象. 本类封装的find()函数全部默认返回对象类型为T,当不为T时使用本函数.
	 * 
	 * @param hql
	 *            查询hql命令。
	 * @param params
	 *            数量可变的参数,按顺序绑定.
	 * @return query对象。
	 */
	@SuppressWarnings("rawtypes")
	private Query createQuery(final String hql, final Object... params) {
		Assert.hasText(hql, "queryString should not be null!");
		Query query = getSession().createQuery(hql);
		
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				if (params[i] instanceof Collection<?>) {
					query.setParameterList("list", (Collection) params[i]);
				}else {
					query.setParameter(i, params[i]);
				}
			}
		}
		return query;
	}

	/**
	 * 根据查询HQL与参数列表创建Query对象.
	 * 
	 * @param values
	 *            命名参数,按名称绑定.
	 */
	private Query createQuery(final String hql, final Map<String, Object> values) {
		Assert.hasText(hql, "hql should not be null!");
		Query query = getSession().createQuery(hql);
		if (values != null) {
			query.setProperties(values);
		}
		return query;
	}

	/**
	 * 根据查询SQL与参数列表创建Query对象. 本类封装的find()函数全部默认返回对象类型为T,当不为T时使用本函数.
	 * 
	 * @param sql
	 *            查询sql命令。
	 * @param params
	 *            数量可变的参数,按顺序绑定.
	 * @return query对象。
	 */
	protected SQLQuery createSQLQuery(final String sql, final Object... params) {
		Assert.hasText(sql, "hql should not be null!");
		SQLQuery query = getSession().createSQLQuery(sql);
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		return query;
	}

	/**
	 * 根据查询SQL与参数列表创建Query对象.
	 * 
	 * @param values
	 *            命名参数,按名称绑定.
	 */
	protected SQLQuery createSQLQuery(final String sql,
			final Map<String, Object> values) {
		Assert.hasText(sql, "sql should not be null!");
		SQLQuery query = getSession().createSQLQuery(sql);
		if (values != null) {
			query.setProperties(values);
		}
		return query;
	}

	/**
	 * 获得映射查询对象
	 * 
	 * @param queryName
	 * @return
	 */
	private Query getNamedQuery(String queryName, final Object... params) {
		Query query = getSession().getNamedQuery(queryName);
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		return query;
	}

	/**
	 * 获得映射查询对象
	 * 
	 * @param queryName
	 * @param values
	 * @return
	 */
	private Query getNamedQuery(String queryName,
			final Map<String, Object> values) {
		Query query = getSession().getNamedQuery(queryName);
		if (null != values) {
			query.setProperties(values);
		}
		return query;
	}

	/**
	 * 根据Criterion条件创建Criteria.
	 * 
	 * 本类封装的find()函数全部默认返回对象类型为T,当不为T时使用本函数.
	 * 
	 * @param criterions
	 *            数量可变的Criterion.
	 */
	protected Criteria createCriteria(final Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(getEntityClass());
		for (Criterion c : criterions) {
			criteria.add(c);
		}
		return criteria;
	}

	/**
	 * 初始化对象. 使用load()方法得到的仅是对象Proxy, 在传到View层前需要进行初始化.
	 * 只初始化entity的直接属性,但不会初始化延迟加载的关联集合和属性. 如需初始化关联属性,可实现新的函数,执行:
	 * Hibernate.initialize(user.getRoles())，初始化User的直接属性和关联集合.
	 * Hibernate.initialize
	 * (user.getDescription())，初始化User的直接属性和延迟加载的Description属性.
	 */
	public void initEntity(T entity) {
		Hibernate.initialize(entity);
	}

	/**
	 * @see #initEntity(Object)
	 */
	public void initEntity(List<T> entityList) {
		for (T entity : entityList) {
			Hibernate.initialize(entity);
		}
	}

	/**
	 * 取得对象的主键名.
	 */
	protected String getIdName() {
		ClassMetadata meta = getSessionFactory().getClassMetadata(
				getEntityClass());
		return meta.getIdentifierPropertyName();
	}

}